package org.openea.eap.module.obpm.service.form;

import com.alibaba.fastjson.JSONObject;
import org.openbpm.base.api.exception.BusinessException;
import org.openbpm.base.core.util.StringUtil;
import org.openbpm.base.core.util.ThreadMapUtil;
import org.openbpm.bus.api.constant.BusTableRelType;
import org.openbpm.bus.api.constant.BusinessPermissionObjType;
import org.openbpm.bus.api.model.IBusTableRel;
import org.openbpm.bus.api.model.IBusinessData;
import org.openbpm.bus.api.model.IBusinessObject;
import org.openbpm.bus.api.model.IBusinessPermission;
import org.openbpm.bus.api.model.permission.IBusObjPermission;
import org.openbpm.bus.api.service.IBusinessDataService;
import org.openbpm.bus.api.service.IBusinessObjectService;
import org.openbpm.bus.api.service.IBusinessPermissionService;
import org.openbpm.bus.api.service.IBusinessTableService;
import org.openbpm.bus.model.BusinessTable;
import org.openbpm.bus.service.impl.BusinessDataPersistenceDbService;
import org.openbpm.form.api.service.IFormDefDataService;
import org.openea.eap.module.obpm.service.custsql.FormCustSqlRelationManager;
import org.openea.eap.module.obpm.model.form.FormDef;
import org.openea.eap.module.obpm.model.form.FormDefData;
import org.openea.eap.module.obpm.model.custsql.FormCustSqlRelation;
import org.openbpm.sys.api.groovy.IGroovyScriptEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class FormDefDataService
        implements IFormDefDataService {
    @Autowired
    FormDefManager formDefManager;
    @Autowired
    IBusinessObjectService businessObjectService;
    @Autowired
    IBusinessTableService businessTableService;
    @Autowired
    IBusinessPermissionService businessPermissionService;
    @Autowired
    IBusinessDataService businessDataService;
    @Autowired
    FormCustSqlRelationManager formCustSqlRelationManager;
    @Autowired
    IGroovyScriptEngine groovyScriptEngine;

    public FormDefData getByFormDefKey(String formDefKey, String id, Boolean isReadOnly) {
        FormDefData formDefData = new FormDefData();
        FormDef formDef = this.formDefManager.getByKey(formDefKey);
        if (formDef == null) {
            throw new BusinessException("FormDef not found, formDefKey=" + formDefKey);
        }

        formDefData.setHtml(formDef.getHtml());
        IBusinessPermission businessPermission = this.businessPermissionService.getByObjTypeAndObjVal(BusinessPermissionObjType.FORM.getKey(), formDef.getKey(), formDef.getBoKey(), true);

        formDefData.setPermission(businessPermission.getPermission(isReadOnly.booleanValue()));
        formDefData.setTablePermission(businessPermission.getTablePermission(isReadOnly.booleanValue()));

        handleInitData(formDef, formDefData);
        handleData(formDef, id, formDefData, businessPermission);
        return formDefData;
    }


    public FormDefData getByFormDefKey(String formKey, String id) {
        return getByFormDefKey(formKey, id, Boolean.valueOf(false));
    }


    private void handleInitData(FormDef formDef, FormDefData formDefData) {
        if (formDefData.getInitData() == null) {
            formDefData.setInitData(new JSONObject());
        }
        JSONObject initData = formDefData.getInitData();
        IBusinessObject businessObject = this.businessObjectService.getFilledByKey(formDef.getBoKey());

        initData.put(formDef.getBoKey(), new JSONObject());

        for (IBusTableRel rel : businessObject.getRelation().list()) {
            initData.getJSONObject(formDef.getBoKey()).put(rel.getTableKey(), getInitData(rel));
        }
    }


    private JSONObject getInitData(IBusTableRel busTableRel) {
        JSONObject table = new JSONObject();
        table.putAll(busTableRel.getTable().initStringData());
        for (IBusTableRel rel : busTableRel.getChildren()) {
            if (BusTableRelType.ONE_TO_ONE.equalsWithKey(rel.getType())) {
                table.put(rel.getTableKey(), getInitData(rel));
            }
        }
        return table;
    }


    private void handleData(FormDef formDef, String id, FormDefData formDefData, IBusinessPermission businessPermission) {
        if (formDefData.getData() == null) {
            formDefData.setData(new JSONObject());
        }

        JSONObject data = formDefData.getData();
        IBusinessObject businessObject = this.businessObjectService.getFilledByKey(formDef.getBoKey());
        businessObject.setPermission((IBusObjPermission) businessPermission.getBusObjMap().get(formDef.getBoKey()));
        IBusinessData bd = this.businessDataService.loadData(businessObject, id);
        boolean isSql = ((Boolean) ThreadMapUtil.getOrDefault("FormDefDataController_getFormDefData_isSql", Boolean.valueOf(false))).booleanValue();
        if (isSql) {
            FormCustSqlRelation fcsr = this.formCustSqlRelationManager.getByFormKey(formDef.getKey());
            if (fcsr != null && StringUtil.isNotEmpty(fcsr.getPreShowScript())) {
                Map<String, Object> map = new HashMap<>();
                map.put(formDef.getBoKey(), bd);
                this.groovyScriptEngine.execute(fcsr.getPreShowScript(), map);
            }
        }

        data.put(formDef.getBoKey(), this.businessDataService.assemblyFormDefData(bd));
    }


    public JSONObject saveFormDefData(JSONObject data, String key, boolean hasScript) {
        JSONObject result = new JSONObject();
        FormDef formDef = this.formDefManager.getByKey(key);
        String boKey = formDef.getBoKey();
        IBusinessPermission permission = this.businessPermissionService.getByObjTypeAndObjVal(BusinessPermissionObjType.FORM.getKey(), key, boKey, true);
        if (!hasScript) {
            result = this.businessDataService.saveFormDefData(data, permission);
            if (result != null && result.containsKey(boKey)) {
                Object bd = result.get(boKey);
                if (bd != null && bd instanceof JSONObject) {
                    result.put("bdpk", ((JSONObject) bd).get("pk"));
                }
            }
            return result;
        }

        IBusinessData bd = this.businessDataService.parseBusinessData(data.getJSONObject(boKey), boKey);
        bd.getBusTableRel().getBusObj().setPermission(permission.getBusObj(boKey));
        FormCustSqlRelation fcsr = this.formCustSqlRelationManager.getByFormKey(formDef.getKey());
        Map<String, Object> map = new HashMap<>();
        map.put(boKey, bd);
        map.put("data", bd);
        // 保存前脚本
        if (StringUtil.isNotEmpty(fcsr.getPreSaveScript())) {
            this.groovyScriptEngine.execute(fcsr.getPreSaveScript(), map);
        }
        bd = this.businessDataService.saveData(bd);
        // 保存后脚本
        if (StringUtil.isNotEmpty(fcsr.getAfterSaveScript())) {
            this.groovyScriptEngine.execute(fcsr.getAfterSaveScript(), map);
        }
        if (bd != null) {
            result.put("bdpk", bd.getPk());
        }
        return result;
    }

    @Autowired
    BusinessDataPersistenceDbService busDataDbService;
    public List<Map<String, Object>> loadDataList(BusinessTable businessTable, List<String> columnName, Map<String, Object> param){
        return this.busDataDbService.loadDataList(businessTable, columnName, param);
    }
}
